#include    "storage.h"
#include    "../utils/datetime.h"

struct StorageData {
    std::string data;
    double deadline;
};

Storage::Storage()
    : _expire(1000 * 60 * 15) //! default expire time : 15 min
    , _lock()
    , _data() {}

Storage::~Storage() {
    std::unique_lock<std::mutex> _(_lock);

    for (auto kv : _data) {
        StorageData * data = kv.second;
        delete data;
    }
}

Storage & Storage::Instance() {
	static Storage * g_storage = new Storage;
    return *g_storage;
}

bool Storage::TryGet(const std::string & key, std::string & out) {
    std::unique_lock<std::mutex> _(_lock);

    auto it = _data.find(key);
    if (it == _data.end()) return false;

    double now = Tick();
    double test = it->second->deadline;
    if (test > 0) {
        if (test <= now) {
            delete it->second;
            _data.erase(it);
            return false;
        } else {
            out = it->second->data;
            it->second->deadline = now + _expire;
            return true;
        }
    } else {
        out = it->second->data;
        return true;
    }
}

void Storage::Set(const std::string & key, const std::string & val, bool never_expire /* = false */) {
    std::unique_lock<std::mutex> _(_lock);
    auto it = _data.find(key);

    if (val.empty()) {
        if (it != _data.end()) {
            delete it->second;
            _data.erase(it);
        }
    } else {
        if (it == _data.end()) {
            StorageData * one = new StorageData;
            one->data = val;
            one->deadline = (never_expire ? 0 : Tick() + _expire);
            _data[key] = one;
        } else {
            it->second->data = val;
            it->second->deadline = (never_expire ? 0 : Tick() + _expire);
        }
    }
}